/**
 * 渲染单条消息到指定容器中
 *
 * @param {Object} message - 要渲染的消息对象，包含消息内容、角色、时间戳等信息
 *
 * @param {HTMLElement} container - 消息要渲染到的容器元素
 *
 * @returns {HTMLElement|null} - 返回渲染后的消息元素，如果 message.noRender 为 true 则返回 null
 */
function renderMessage(message, container) {
	// 如果消息标记为不渲染，则直接返回
	if (message.noRender) return;
	/**
	 * 创建消息的根元素
	 */
	const messageElement = document.createElement("div");
	/**
	 * 获取消息的时间戳，如果没有则使用系统当前时间
	 */
	const timestamp = message.timestamp || getSystemTime();
	/**
	 * 构建语音播放按钮的 HTML 字符串
	 *
	 * 如果消息角色是助手，则返回语音播放按钮的 HTML，否则返回空字符串
	 *
	 * @returns {string} - 语音播放按钮的 HTML 字符串或空字符串
	 */
	function buildSoundButton() {
		if (message.role === "assistant") {
			return `<button class="chat-action-button play_speech_button" title="播放语音"><i class="fas fa-volume-up"></i></button>`
		}
		return "";
	};
	/**
	 * 定义删除按钮的 HTML 字符串
	 */
	const buildDeleteButton = `<button class="chat-action-button delete_message_button" title="删除消息"><i class="fas fa-trash"></i></button>`;
	// 为消息根元素添加基础类名
	messageElement.classList.add("message");
	// 设置消息元素的初始 HTML 结构
	messageElement.innerHTML = `
        <div class="message-header">
            <span>${message.role === "user" ? "用户" : "月华"}</span>
            <span>${timestamp}</span>
        </div>
        ${message.imageUrl ? `<div class="image-content"> <img src="${message.imageUrl}" alt="上传的图片" style="max-width: 100%; border-radius: 8px;"> </div>` : ""}
        <div class="markdown-content">${message.content}</div>
        <div class="message-actions-panel">
            <button class="chat-action-button copy_message_button" title="复制消息">
                <i class="fas fa-copy"></i>
            </button>
			${buildDeleteButton}
            ${buildSoundButton()}
        </div>
    `;
	/**
	 * 获取消息内容元素
	 */
	const contentElement = messageElement.querySelector(".markdown-content");
	// 处理消息内容中的思考标签
	contentElement.innerHTML = processThinkTags(message.content);
	// 生成集合渲染
	generateCollectionRendering(contentElement);
	// 如果消息是提示消息，则移除操作面板和头部，并添加文件消息类名
	if (message?.isPrompt) {
		// 如果消息没有文件链接，则移除消息的操作面板
		if (!message?.fileUrl) messageElement.querySelector(".message-actions-panel").remove();
		// 移除消息的头部信息
		messageElement.querySelector(".message-header").remove();
		// 为消息元素添加文件消息类名，用于样式控制
		messageElement.classList.add("file-message");
		/**
		 * 定义边框颜色数组
		 */
		const colors = [
			'--status-218838',
			'--status-3a5a8a',
			'--status-4a6fa5',
			'--status-6c9bcf',
			'--status-8a2be2',
			'--status-9d6bff',
			'--status-dc3545',
			'--status-fbbf24',
			'--status-ffc107',
			'--status-20c997',
			'--status-ff6b9c',
		];
		// 随机选择一个边框颜色
		messageElement.style.borderColor = `var(${colors[RandomFloor(0, colors.length)]})`;
	}
	// 如果是用户消息，则添加用户消息类名
	else if (message.role === "user") messageElement.classList.add("user-message");
	// 否则为助手消息，添加助手消息类名
	else messageElement.classList.add("assistant-message");
	// 如果存在图片消息
	if (message.imageUrl) messageElement.classList.add("image-message");
	// 将消息元素添加到容器中
	container.appendChild(messageElement);
	// 绑定消息的操作按钮事件
	bindMessageActionEvents(messageElement, message);
	// 滚动容器到最底部，确保新消息可见
	setTimeout(() => container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' }), 1000);
	// 对消息中的代码块进行语法高亮处理
	messageElement.querySelectorAll('pre code').forEach(block => hljs.highlightElement(block));
	// 绑定代码执行按钮事件
	bindCodeExecuteButtons(messageElement);
	// 返回渲染后的消息元素
	return messageElement;
};

/**
 * 无迹渲染消息
 *
 * @param {string} message - 要渲染的消息内容
 *
 * @param {HTMLElement} container - 消息要渲染到的容器元素
 *
 * @returns {HTMLElement|null} - 返回渲染后的消息元素，如果 message.noRender 为 true 则返回 null
 */
function tracelessRenderMessage(message, container) {
	return renderMessage(createMessageObject("assistant", message, false, true), container);
};

/**
 * 渲染对话历史中的所有消息到指定容器中
 *
 * @param {HTMLElement} container - 消息要渲染到的容器元素
 *
 * @returns {void} 该函数不返回任何值
 */
async function renderAllMessages(container) {
	// 清空容器内的现有内容
	container.innerHTML = '';
	// 滚动到容器顶部
	container.scrollTo({ top: 0, behavior: 'smooth' })
	// 遍历对话历史中的每条消息
	conversationHistory.forEach(
		message => {
			/**
			 * 调用 renderMessage 函数渲染单条消息到容器中
			 */
			const newMessage = renderMessage(message, container);
			// 若消息渲染成功，则查找消息中的所有思考折叠按钮
			newMessage?.querySelectorAll(".toggle_think_button").forEach(bindFoldingButton);
		}
	);
	/**
	 * 统计对话历史中标记为不渲染的消息数量
	 */
	const hiddenCount = conversationHistory.filter(msg => msg.noRender).length;
	// 若存在标记为不渲染的消息，则创建一条提示消息告知用户剩余文件信息数量
	if (hiddenCount >= 1) tracelessRenderMessage(`月华这还有 **${hiddenCount}** 个文件片段哦~~`, chatHistoryPanel);
};

/**
 * 重新加载助手消息并处理其中的 Markdown 内容，执行一系列渲染和绑定操作
 *
 * @param {string} assistantMessage - 助手返回的消息内容
 *
 * @param {HTMLElement} contentElement - 助手消息的内容元素
 *
 * @returns {void} 该函数不返回任何值
 */
function reloadMessageAndMarkdown(assistantMessage, contentElement) {
	/**
	 * 移除 markdown 代码块的标记，只保留代码块内的内容
	 */
	const cleanMessage = assistantMessage.replace(/```markdown([\s\S]*?)```/gi, "$1").replace(/```markdown/gi, "");
	/**
	 *  获取最后一条助手消息的内容
	 */
	const lastMessage = conversationHistory[conversationHistory.length - 1];
	// 更新最后一条助手消息的内容
	lastMessage.content = cleanMessage;
	/**
	 * 获取最后一条助手消息的元素
	 *
	 * 通过查找离 contentElement 最近的 .message 类元素来定位消息元素
	 */
	const messageElement = contentElement.closest('.message');
	// 若消息元素不存在，则说明没有合适的消息需要处理，直接返回
	if (!messageElement) return;
	/**
	 * 在消息元素中查找 .markdown-content 类元素作为内容容器
	 */
	const contentContainer = messageElement.querySelector('.markdown-content');
	// 若消息内容容器不存在，则无法进行内容渲染，直接返回
	if (!contentContainer) return;
	// 重新处理内容，将处理后的消息内容通过 processThinkTags 函数处理后插入到内容容器中
	contentContainer.innerHTML = processThinkTags(cleanMessage);
	// 重新绑定思考标签的切换事件，确保交互功能正常
	messageElement.querySelectorAll(".toggle_think_button").forEach(bindFoldingButton);
	// 重新绑定代码块的语法高亮事件，对消息中的代码块进行高亮显示
	messageElement.querySelectorAll('pre code').forEach(block => hljs.highlightElement(block));
	// 重新生成 Mermaid 图表，对内容容器中的 Mermaid 代码块进行图表渲染
	generateMermaidChart(contentContainer);
	// 重新生成 ECharts 图表，对内容容器中的 ECharts 代码块进行图表渲染
	generateEChartsChart(contentContainer);
	// 自动渲染页面中的公式（使用$...$或\(...\)语法）
	renderMathInElement(contentContainer,
		{
			delimiters: [
				{ left: '$$', right: '$$', display: true },
				{ left: '$', right: '$', display: false },
				{ left: '\\(', right: '\\)', display: false },
				{ left: '\\[', right: '\\]', display: true }
			],
			throwOnError: false
		}
	);
	// 重新绑定操作按钮事件，确保消息的操作按钮功能正常
	bindMessageActionEvents(messageElement, lastMessage);
	// 滚动到消息底部，确保用户能够看到最新的消息
	chatHistoryPanel.scrollTo({ top: chatHistoryPanel.scrollHeight, behavior: 'smooth' });
}